/* Laboratorio # 2 - Administración de bases de datos
 Jorge Fallas Ramos         402090469
 José Roberto Sánchez       115400070
 Daniel Villalobos Venegas  402110100
 */
package monitorinitdb.Vista;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.HeadlessException;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.BevelBorder;
import javax.swing.filechooser.FileNameExtensionFilter;
import monitorinitdb.ConectorOracle;
import monitorinitdb.Init;
import monitorinitdb.Build;
import monitorinitdb.ConectorUnix;
import monitorinitdb.escritoraSQL;

public class VentConfig extends JFrame implements ActionListener {

    public static void setConexion(ConectorOracle con) {
        if (instance != null) {
            instance.con = con;
        }
    }

    private void cambiaDir(String name) {
        try {
            File f = obtDir();
            if (f != null) {
                for (JTextField tex : campos) {
                    if (tex.getName().equals(name)) {
                        tex.setText(f.getAbsolutePath());
                        break;
                    }
                }
            }
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(null, ex.getMessage(), "Error", JOptionPane.WARNING_MESSAGE);
        }
    }

    ConectorOracle con;

    public void setConnection(ConectorOracle c) {
        con = c;
    }

    private File obtDir() {
        int status = selDir.showOpenDialog(null);
        if (status == JFileChooser.APPROVE_OPTION) {
            return selDir.getSelectedFile();
        }
        return null;
    }

    private JPanel genPanArchiveLog() {
        JPanel l = new panelE();
        JButton b;
        JTextField tex;
        l.setLayout(new BoxLayout(l, BoxLayout.Y_AXIS));

        JPanel m = new panelE(new FlowLayout());
        m.add(new JLabel("Seleccione el directorio a usar:"));
        posDir = new JComboBox<>();
        posDir.setPreferredSize(new Dimension(50, 35));
        m.add(posDir);
        b = new JButton(acciones[2]);
        b.setActionCommand(acciones[2]);
        b.addActionListener(this);
        m.add(b);
        l.add(m);

        m = new panelE(new FlowLayout());
        m.add(new JLabel("Tiempo entre checkpoint:"));
        tex = new JTextField();
        tex.setPreferredSize(new Dimension(150, 35));
        m.add(tex);
        l.add(m);
        camposArchiv.add(tex);
        m.setName("Tiempo entre checkpoint");
        tex.setName("Tiempo entre checkpoint");

        m = new panelE(new FlowLayout());
        m.add(new JLabel("Tamaño entre checkpoint:"));
        tex = new JTextField();
        tex.setPreferredSize(new Dimension(150, 35));
        m.add(tex);
        l.add(m);
        camposArchiv.add(tex);
        tex.setName("Tamaño entre checkpoint");
        m.setName("Tamaño entre checkpoint");
        return l;
    }

    private class panelE extends JPanel {

        public panelE() {
            super();
        }

        public panelE(LayoutManager m) {
            super(m);
        }

        @Override
        public void setEnabled(boolean enabled) {
            super.setEnabled(enabled); //To change body of generated methods, choose Tools | Templates.
            for (Component c : getComponents()) {
                c.setEnabled(enabled);
            }
        }
    };

    public static VentConfig instance;
    ArrayList<JTextField> campos, camposArchiv, camposTS;

    JFileChooser selArchivo, selDir;

    String[] acciones = {"Seleccionar archivo",
        "Seleccionar Directorio",
        "Agregar Archive",
        "Agregar Tablespace",
        "Agregar Redos y Control Files",
        "Scripts",
        "Limpiar",
        "Limpiar Todo",
        "Instanciar!"
    };

    String[] tableSpaceDef = {"SYSTEM", "SYSAUX", "TEMP", "UNDO"};
    String[] needs = {"<html>Direccion de guardado<br>init.ora y build.sql</html>",
        "Direccion de creación de archivos",
        "Nombre de la base de datos",
        "Memory Target",
        "Tamaño del bloque de datos",
        "Nombre del tablespace UNDO",
        "db_recovery_file_dest",
        "db_recovery_file_dest_size"
    };

    JCheckBox archiv;
    JPanel panArchiv;
    JComboBox<Integer> posDir;

    public static VentConfig getInstance() {
        if (instance == null) {
            instance = new VentConfig();
        }
        return instance;
    }

    public VentConfig() throws HeadlessException {
        campos = new ArrayList<>();
        camposArchiv = new ArrayList<>();
        camposTS = new ArrayList<>();
        configInicial();
        configSelArchiv();
        configSelDir();
        configComponentes();
    }

    private void configComponentes() {
        JPanel end = new JPanel(new BorderLayout());

        JPanel comp = new JPanel();
        comp.setLayout(new BoxLayout(comp, BoxLayout.Y_AXIS));

        JPanel p = genPanel(needs[0], 3);

        JButton b = genOpenDir();
        p.add(b);
        b.setName(needs[0] + "_");
        comp.add(p);
        comp.add(Box.createGlue());

        p = genPanel(needs[1], 3);

        b = genOpenDir();
        b.setName(needs[1] + "_");
        p.add(b);
        comp.add(p);
        comp.add(Box.createGlue());

        p = genPanel(needs[2], 2);
        comp.add(p);
        comp.add(Box.createGlue());

        p = genPanel(needs[3], 2);
        comp.add(p);
        comp.add(Box.createGlue());

        p = genPanel(needs[4], 2);
        comp.add(p);
        comp.add(Box.createGlue());

        p = genPanel(needs[5], 2);
        comp.add(p);
        comp.add(Box.createGlue());

        p = genPanel(needs[6], 3);
        b = new JButton(acciones[1]);
        b.setActionCommand(acciones[1]);
        b.setName(needs[6] + "_");
        b.addActionListener(this);
        p.add(b);
        comp.add(p);
        comp.add(Box.createGlue());

        p = genPanel(needs[7], 2);
        comp.add(p);
        comp.add(Box.createGlue());

        p = new JPanel(new FlowLayout());
        archiv = new JCheckBox("Activar Archive Mode");
        archiv.setHorizontalTextPosition(JCheckBox.LEFT);
        archiv.setActionCommand("ActivaArchive");
        archiv.addActionListener(this);
        p.add(archiv);
        comp.add(p);

        panArchiv = genPanArchiveLog();

        comp.add(panArchiv);
        panArchiv.setEnabled(false);
        panArchiv.setBorder(BorderFactory.createSoftBevelBorder(BevelBorder.RAISED));

        JPanel m = new JPanel();
        m.setLayout(new BoxLayout(m, BoxLayout.Y_AXIS));
        b = new JButton(acciones[3]);
        b.addActionListener(this);
        m.add(b);

        for (String s : tableSpaceDef) {
            m.add(genTS(s));
        }

        comp.add(m);
        end.add(comp, BorderLayout.CENTER);
        this.add(end, BorderLayout.CENTER);
        this.add(panelBtn(), BorderLayout.SOUTH);
        JPanel lm = new JPanel();
        lm.setLayout(new BoxLayout(lm, BoxLayout.PAGE_AXIS));
        b = new JButton("Salir");
        b.addActionListener(this);
        lm.add(b);
        b = new JButton("Desconectar");
        b.addActionListener(this);
        lm.add(b);
        this.add(lm, BorderLayout.EAST);
        lm.add(new JLabel(new ImageIcon(getClass().getResource("/monitorinitdb/Vista/Imagenes/bannerConfig.png"))));
        lm.add(new JLabel(new ImageIcon(getClass().getResource("/monitorinitdb/Vista/Imagenes/bannerConfig.png"))));
        end.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
    }

    private JPanel panelBtn() {
        JPanel p = new JPanel(new FlowLayout());
        JButton b;
        for (int i = 4; i < acciones.length; i++) {
            b = new JButton(acciones[i]);
            b.addActionListener(this);
            p.add(b);
        }
        return p;
    }

    private JButton genOpenDir() {
        JButton b = new JButton(acciones[1]);
        b.setActionCommand(acciones[1]);
        b.addActionListener(this);
        return b;
    }

    private JPanel genPanel(String need, int col) {
        JPanel p = new JPanel(new GridLayout(1, col));
        p.add(new JLabel(need + ":"));
        JTextField tex = new JTextField();
        tex.setPreferredSize(new Dimension(200, 35));
        p.add(tex);
        tex.setName(need + "_");
        if (col == 3) {
            tex.setEditable(false);
        }
        campos.add(tex);
        p.setName(need + "_");
        return p;
    }

    private JPanel genTS(String nom) {
        int cont = 0;

        JPanel l = new JPanel(new FlowLayout(FlowLayout.LEFT));
        JTextField tex;
        l.add(new JLabel("Tablespace " + nom));
        l.add(new JLabel("DataFile:"));
        tex = new JTextField();
        tex.setPreferredSize(new Dimension(100, 35));
        tex.setName(nom + (cont + 1));
        tex.setEditable(false);
        l.add(btSelArchivo(tex.getName()));
        camposTS.add(tex);
        cont++;
        l.add(tex);

        l.add(new JLabel("Tamaño:"));
        tex = new JTextField();
        camposTS.add(tex);
        tex.setName(nom);
        tex.setPreferredSize(new Dimension(65, 35));
        l.add(tex);
        tex.setName(nom + (cont + 1));
        cont++;

        if (nom.equals(tableSpaceDef[0]) || nom.equals(tableSpaceDef[1])) {
            tex = new JTextField();
            tex.setPreferredSize(new Dimension(100, 35));
            l.add(new JLabel("Autoextend on:"));
            l.add(tex);
            tex.setName(nom + (cont + 1));
            cont++;
            camposTS.add(tex);
        }
        return l;
    }

    static void incrementArchiv() {
        if (instance != null) {
            instance.posDir.addItem(instance.posDir.getItemCount() + 1);
        }
    }

    static void decrementArchiv() {
        if (instance != null) {
            if (instance.posDir.getItemCount() != 1) {
                instance.posDir.removeItemAt(instance.posDir.getItemCount() - 1);
            } else {
                instance.posDir.removeAllItems();
            }
            instance.getContentPane().revalidate();
            instance.panArchiv.repaint();
        }
    }

    private void configInicial() {
        if (System.getProperty("os.name").toLowerCase().equals("linux")) {
            setPreferredSize(new Dimension(950, 680));
        } else {
            setPreferredSize(new Dimension(950, 720));
        }
        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                salir();
            }
        });

        setTitle("Ventana Configuración");
    }

    private void configSelDir() {
        selDir = new JFileChooser();
        selDir.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        selDir.setFileFilter(new FileNameExtensionFilter("Carpetas", "*"));
        selDir.setDialogType(JFileChooser.OPEN_DIALOG);
    }

    private void configSelArchiv() {
        selArchivo = new JFileChooser();
        selArchivo.setDialogType(JFileChooser.SAVE_DIALOG);
        selArchivo.setFileFilter(new FileNameExtensionFilter("Datafile", "dbf"));
    }

    public void limpiar() {
        for (JTextField j : campos) {
            j.setText("");
        }

        for (JTextField j : camposArchiv) {
            j.setText("");
        }
        for (JTextField j : camposTS) {
            j.setText("");
        }
    }

    public void mostrar() {
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
        System.out.println(camposTS.size());
    }

    public static void main(String[] args) {
        try {
            UIManager.LookAndFeelInfo[] list = UIManager.getInstalledLookAndFeels();
            UIManager.setLookAndFeel(list[1].getClassName());
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
            System.err.println(ex.getMessage());
        }
        try {
            VentConfig.getInstance().setConnection(new ConectorUnix("sys", "root"));
        } catch (IOException ex) {
            System.err.println(ex.getMessage());
        }
        VentConfig.getInstance().mostrar();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        switch (e.getActionCommand()) {
            case "Agregar Archive": {
                setVisible(false);
                VentanaArchiveLog.getInstance().mostrar();
            }
            break;
            case "Instanciar!": {
                try {
                    creaInit();
                    creaBuild();
                    String ruta = creaConfig();
                    con.ejecutaInstruccion(ruta);
                    JOptionPane.showMessageDialog(null, "Base de datos instanciada");
                } catch (Exception ex) {
                    JOptionPane.showMessageDialog(null, ex.getMessage(), "Error", JOptionPane.WARNING_MESSAGE);
                }
            }
            break;
            case "Agregar Redos y Control Files": {
                setVisible(false);
                VentArchiv.getInstance().mostrar();
            }
            break;
            case "Agregar Tablespace": {
                setVisible(false);
                VentTableSpace.getInstance().mostrar();
            }
            break;
            case "Scripts": {
                setVisible(false);
                VentScripts.getInstance().mostrar();
            }
            break;
            case "Limpiar Todo": {
                limpiar();
                VentTableSpace.clean();
                VentArchiv.clean();
                VentanaArchiveLog.clean();
                archiv.setSelected(false);
                panArchiv.setEnabled(false);
            }
            break;
            case "Limpiar": {
                limpiar();
                archiv.setSelected(false);
                panArchiv.setEnabled(false);
            }
            break;
            case "Seleccionar Archivo": {
                JButton bt = (JButton) e.getSource();
                try {
                    cambiaDataFile(bt.getName());
                } catch (Exception ex) {
                    JOptionPane.showMessageDialog(null, ex.getMessage(), "Error", JOptionPane.WARNING_MESSAGE);
                }
            }
            break;
            case "Seleccionar Directorio": {
                JButton bt = (JButton) e.getSource();
                cambiaDir(bt.getName());
            }
            break;
            case "ActivaArchive": {
                panArchiv.setEnabled(archiv.isSelected());
            }
            break;
            case "Desconectar": {
                setVisible(false);
                Ventana.getInstance().mostrar();
            }
            break;
            case "Salir": {
                salir();
            }
            break;
            default:
                throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        }
    }

    private void cambiaDataFile(String name) throws Exception {
        int status = selArchivo.showSaveDialog(null);
        JTextField elegido = null;
        if (status == JFileChooser.APPROVE_OPTION) {
            File f = selArchivo.getSelectedFile();

            if (!f.getAbsolutePath().endsWith(".dbf")) {
                f = new File(f.getAbsolutePath() + ".dbf");
            }

            if (f.exists()) {
                throw new Exception("Datafile ya creado");
            }

            for (JTextField tex : camposTS) {
                if (tex.getText().equals(f.getAbsolutePath())) {
                    throw new Exception("Archivo definido para otro tablespace");
                }
                if (tex.getName().equals(name)) {
                    elegido = tex;
                }
            }

            String tSExtra = VentTableSpace.getTableSpace();
            if (tSExtra != null) {
                if (tSExtra.contains(f.getAbsolutePath())) {
                    throw new Exception("Archivo definido para otro tablespace");
                }
            }

            if (elegido != null) {
                elegido.setText(f.getAbsolutePath());
            }
        }
    }

    private JButton btSelArchivo(String name) {
        JButton b = new JButton("<html>Seleccionar<br>Archivo</html>");
        b.setActionCommand("Seleccionar Archivo");
        b.addActionListener(this);
        b.setName(name);
        return b;
    }

    private void salir() {
        int s = JOptionPane.showConfirmDialog(null, "Desea salir de la aplicación", "Salir?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
        if (s == JOptionPane.YES_OPTION) {
            System.exit(0);
        }
    }

    public boolean getArchivActivo() {
        return archiv.isSelected();
    }

    public String obtDirGuardado() throws Exception {
        if (!campos.get(0).getText().equals("")) {
            return campos.get(0).getText();
        }
        throw new Exception("Direccion de carpeta para guardar los archivos no seleccionado");
    }

    public String obtCreacionArchivos() {
        return campos.get(1).getText();
    }

    public String obtLogTrace() throws Exception {
        if (archiv.isSelected()) {
            if (posDir.getSelectedItem() != null) {
                return "ALTER SYSTEM SET LOG_ARCHIVE_TRACE = " + posDir.getSelectedItem();
            }
            throw new Exception("Direccion de carpeta para archive mode no seleccionado");
        }
        return null;
    }//para build

    public String obtSystem() throws Exception {
        for (int i = 0; i < 3; i++) {
            if (camposTS.get(i).getName().equals("")) {
                throw new Exception("Campo del tablespace SYSTEM no definido");
            }
        }
        return "DATAFILE '" + camposTS.get(0).getText() + "' SIZE " + camposTS.get(1).getText() + " AUTOEXTEND ON NEXT " + camposTS.get(2).getText() + " MAXSIZE UNLIMITED EXTENT MANAGEMENT LOCAL";
    }//ya

    public String obtSysAux() throws Exception {
        for (int i = 3; i < 6; i++) {
            if (camposTS.get(i).getName().equals("")) {
                throw new Exception("Campo del tablespace SYSAUX no definido");
            }
        }
        return "SYSAUX DATAFILE '" + camposTS.get(3).getText() + "' SIZE " + camposTS.get(4).getText() + " AUTOEXTEND ON NEXT " + camposTS.get(5).getText() + " MAXSIZE UNLIMITED";
    }//para el build

    public String obtTemp() throws Exception {
        for (int i = 6; i < 8; i++) {
            if (camposTS.get(i).getName().equals("")) {
                throw new Exception("Campo del tablespace TEMP no definido");
            }
        }
        return " DEFAULT TEMPORARY TABLESPACE TEMP TEMPFILE '" + camposTS.get(6).getText() + "' SIZE " + camposTS.get(7).getText() + ";";
    }// para el build crea el temp

    public String obtUndoTS() throws Exception {
        for (int i = 8; i < 10; i++) {
            if (camposTS.get(i).getName().equals("")) {
                throw new Exception("Campo del tablespace UNDO no definido");
            }
        }
        if (camposTS.get(8).getName().equals("")) {
            throw new Exception("Nombre del tablespace UNDO no definido");
        }

        return "UNDO TABLESPACE " + obtNomUndo() + " DATAFILE '" + camposTS.get(8).getText() + "' SIZE " + camposTS.get(9).getText();
    }//para build se concatena con el lab anterior  + obtTemp()

    public String obtMemoryTarget() {
        return campos.get(3).getText();
    }//ya

    public String obtTiempoArchive() throws Exception {
        return camposArchiv.get(0).getText();
    }//ya

    public String obtTamArchive() throws Exception {
        return camposArchiv.get(1).getText();
    }//ya

    public String obtTamBloque() throws Exception {
        if (campos.get(4).getText().equals("")) {
            throw new Exception("Tamaño del bloque no definido");
        }
        return campos.get(4).getText();
    }//ya

    public String obtNomBD() throws Exception {
        if (campos.get(2).getText().equals("")) {
            throw new Exception("Nombre de la base de datos no definido");
        }
        return campos.get(2).getText();
    }//ya

    public String obtDirRecov() throws Exception {
        if (campos.get(6).getText().equals("")) {
            throw new Exception("Direccion de recuperación no definido");
        }
        return campos.get(6).getText();
    }//ya

    public String obtRecovSize() throws Exception {
        return campos.get(7).getText();
    }//ya

    public String obtNomUndo() throws Exception {
        if (campos.get(5).getText().equals("")) {
            throw new Exception("Nombre del tablespace UNDO no definido");
        }
        return campos.get(5).getText();
    }//ya

    public Init creaInit() {

        try {
            return new Init(obtNomBD(), obtMemoryTarget(), "150", obtTamBloque(),
                    obtDirRecov(), obtRecovSize(), obtNomUndo(), VentArchiv.getControlFiles(),
                    "11.2.0", obtTiempoArchive(), obtTamArchive(), obtDirGuardado() + "/init.ora");

        } catch (Exception ex) {
            JOptionPane.showMessageDialog(null, ex.getMessage(), "Error", JOptionPane.WARNING_MESSAGE);
        }
        return null;
    }

    public Build creaBuild() {
        try {
            Build b = new Build(obtCreacionArchivos(), obtNomBD(), VentArchiv.getRedos(),
                    obtSystem(), obtSysAux(), obtUndoTS() + obtTemp(), VentTableSpace.getTableSpace(),
                    VentanaArchiveLog.getArchive(), obtLogTrace(), obtTiempoArchive(), "", "", obtDirGuardado() + "/build.sql");
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(null, ex.getMessage(), "Error", JOptionPane.WARNING_MESSAGE);
        }
        return null;
    }

    public String creaConfig() {
        try {
            String[] ruts = VentScripts.getScripts();
            escritoraSQL escritora = new escritoraSQL(obtDirGuardado() + "/ejecucion.sql");
            String rutas = "";

            if (ruts != null) {
                for (int i = 0; i < ruts.length; i++) {
                    rutas = rutas + "@" + ruts[i] + "\n";
                }
            }
            String os = System.getProperty("os.name").toLowerCase();
            if (os.equals("linux")) {
                escritora.creaBD(con.getUser(), con.getPass(), obtDirGuardado() + "/init.ora", obtDirGuardado() + "/build.sql", rutas, archiv.isSelected());
            } else if (os.equals("windows 7")) {
                escritora.creaBD(con.getUser(), con.getPass(), obtDirGuardado() + "\\init.ora", obtDirGuardado() + "\\build.sql", rutas, archiv.isSelected());
            } else {
                throw new Exception("Sistema operativo " + os + " no soportado\nEspere a la siguiente versión de la aplicación");
            }
            return escritora.getEjecucion();
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(null, ex.getMessage(), "Error", JOptionPane.WARNING_MESSAGE);
        }
        return null;
    }

    public static String[] getTSData() {
        if (instance != null) {
            String[] vec = new String[4];
            vec[0] = instance.camposTS.get(0).getText();
            vec[1] = instance.camposTS.get(3).getText();
            vec[2] = instance.camposTS.get(6).getText();
            vec[3] = instance.camposTS.get(8).getText();
            return vec;
        }
        return null;
    }
}
